#region (c) 2014 THN Solutions LLC. - All rights reserved
/*
Simplified BSD License (BSD)
Copyright (c) 2014, THN Solutions LLC. ( www.ThnSolutions.com )
Author: Nguyễn, M. Hải                 ( www.Minh-Hai.com     )
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice, this 
      list of conditions and the following disclaimer.

    * Redistributions in binary form must reproduce the above copyright notice, 
      this list of conditions and the following disclaimer in the documentation 
      and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
POSSIBILITY OF SUCH DAMAGE.
*/
#endregion

#region Record of Change
//             							CHANGE HISTORY
// -------------------------------------------------------------------------------------
// |   DATE    | DEVELOPER  | DESCRIPTION                                              |
// -------------------------------------------------------------------------------------
// | 08-Nov-09 | HaiNM      | First creation.                                          |
// -------------------------------------------------------------------------------------
//
#endregion

#region Record of Audit
//             							REVIEW HISTORY
// -------------------------------------------------------------------------------------
// |   DATE    | REVIEWER   | NOTES                                                    |
// -------------------------------------------------------------------------------------
// -------------------------------------------------------------------------------------
//
#endregion

#region Using directives
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.ComponentModel;
using System.Windows.Forms;

using Thn;
using Thn.Interface.Vcl.Themes;
#endregion

namespace Thn.Interface.Vcl
{
    /// <summary>
    /// Base class for textbox, numberbox. Provides an object wrapper for Windows Forms' textbox.
    /// </summary>
    [ToolboxItem(false), DefaultValue("Title"), DefaultProperty("ValueChanged")]
#if DEBUG
    public
#else
    public
#endif
 abstract class EditBox : ControlBase
    {
        #region Fields
        /// <summary>
        /// The inner textbox that is hosted by this control.
        /// </summary>
        public NativeWindowsTextBox Inner = null;
        /// <summary>
        /// Gets/Sets whether this box should show a drop down button.
        /// </summary>
        internal bool mShowDropButton = false;
        /// <summary>
        /// Move caret to end of text when set focus for textbox.
        /// <para>Default is false. Grid Cell editors usually set this to true.</para>
        /// </summary>
        internal bool MoveToEndOnFocus = false;
        #endregion

        #region Properties

        #region Border Styles

        #region Border Style Normal
        private EditBoxBorderStyle mBorderStyleNormal = EditBoxBorderStyle.Default;
        /// <summary>
        /// Gets/Sets border style while in normal state.
        /// </summary>
        [Browsable(true), DefaultValue(EditBoxBorderStyle.Default), Category("Appearance"), Description("Border style for normal state")]
        public EditBoxBorderStyle BorderStyleNormal
        {
            get { return mBorderStyleNormal; }
            set
            {
                mBorderStyleNormal = value;
                Invalidate();
            }
        }
        #endregion

        #region Border Style Over
        private EditBoxBorderStyle mBorderStyleOver = EditBoxBorderStyle.Default;
        /// <summary>
        /// Gets/Sets border style while in mouse over state.
        /// </summary>
        [Browsable(true), DefaultValue(EditBoxBorderStyle.Default), Category("Appearance"), Description("Border style for mouse over state")]
        public EditBoxBorderStyle BorderStyleOver
        {
            get { return mBorderStyleOver; }
            set
            {
                mBorderStyleOver = value;
                Invalidate();
            }
        }
        #endregion

        #region Border Style Focused
        private EditBoxBorderStyle mBorderStyleFocused = EditBoxBorderStyle.Default;
        /// <summary>
        /// Gets/Sets border style while in focused state.
        /// </summary>
        [Browsable(true), DefaultValue(EditBoxBorderStyle.Default), Category("Appearance"), Description("Border style for focused state")]
        public EditBoxBorderStyle BorderStyleFocused
        {
            get { return mBorderStyleFocused; }
            set
            {
                mBorderStyleFocused = value;
                Invalidate();
            }
        }
        #endregion

        #region Border Style Disabled
        private EditBoxBorderStyle mBorderStyleDisabled = EditBoxBorderStyle.Default;
        /// <summary>
        /// Gets/Sets border style while in Disabled state.
        /// </summary>
        [Browsable(true), DefaultValue(EditBoxBorderStyle.Default), Category("Appearance"), Description("Border style for disabled state")]
        public EditBoxBorderStyle BorderStyleDisabled
        {
            get { return mBorderStyleDisabled; }
            set
            {
                mBorderStyleDisabled = value;
                Invalidate();
            }
        }
        #endregion

        #region Border Style Area
        private EditBoxStyleArea mBorderStyleArea = EditBoxStyleArea.EditOnly;
        /// <summary>
        /// Gets/Sets the area for applying border style.
        /// </summary>
        [Browsable(true), DefaultValue(EditBoxStyleArea.EditOnly), Category("Appearance"), Description("Area for applying border style")]
        public EditBoxStyleArea BorderStyleArea
        {
            get { return mBorderStyleArea; }
            set
            {
                mBorderStyleArea = value;
                Invalidate();
            }
        }
        #endregion

        #endregion

        #region Fill Styles

        #region Fill Style Normal
        private EditBoxFillStyle mFillStyleNormal = EditBoxFillStyle.Default;
        /// <summary>
        /// Gets/Sets fill style for normal state.
        /// </summary>
        [Browsable(true), DefaultValue(EditBoxFillStyle.Default), Category("Appearance"), Description("Fill style for normal state")]
        public EditBoxFillStyle FillStyleNormal
        {
            get { return mFillStyleNormal; }
            set
            {
                mFillStyleNormal = value;
                Invalidate();
            }
        }
        #endregion

        #region Fill Style Focused
        private EditBoxFillStyle mFillStyleFocused = EditBoxFillStyle.Default;
        /// <summary>
        /// Gets/Sets fill style for focused state.
        /// </summary>
        [Browsable(true), DefaultValue(EditBoxFillStyle.Default), Category("Appearance"), Description("Fill style for focused state")]
        public EditBoxFillStyle FillStyleFocused
        {
            get { return mFillStyleFocused; }
            set
            {
                mFillStyleFocused = value;
                Invalidate();
            }
        }
        #endregion

        #region Fill Style Over
        private EditBoxFillStyle mFillStyleOver = EditBoxFillStyle.Default;
        /// <summary>
        /// Gets/Sets fill style for mouse over state.
        /// </summary>
        [Browsable(true), DefaultValue(EditBoxFillStyle.Default), Category("Appearance"), Description("Fill style for mouse over state")]
        public EditBoxFillStyle FillStyleOver
        {
            get { return mFillStyleOver; }
            set
            {
                mFillStyleOver = value;
                Invalidate();
            }
        }
        #endregion

        #region Fill Style Disabled
        private EditBoxFillStyle mFillStyleDisabled = EditBoxFillStyle.Default;
        /// <summary>
        /// Gets/Sets fill style for disabled state.
        /// </summary>
        [Browsable(true), DefaultValue(EditBoxFillStyle.Default), Category("Appearance"), Description("Fill style for disabled state")]
        public EditBoxFillStyle FillStyleDisabled
        {
            get { return mFillStyleDisabled; }
            set
            {
                mFillStyleDisabled = value;
                Invalidate();
            }
        }
        #endregion

        #region Fill Style Area
        private EditBoxStyleArea mFillStyleArea = EditBoxStyleArea.EditOnly;
        /// <summary>
        /// Gets/Sets the area for applying fill style.
        /// </summary>
        [Browsable(true), DefaultValue(EditBoxStyleArea.EditOnly), Category("Appearance"), Description("Area for applying fill style")]
        public EditBoxStyleArea FillStyleArea
        {
            get { return mFillStyleArea; }
            set
            {
                mFillStyleArea = value;
                Invalidate();
            }
        }
        #endregion

        #endregion

        #region Text
        private string mText;
        /// <summary>
        /// Gets/Sets the display text.
        /// </summary>
        public override string Text
        {
            get
            {
                mText = Inner.Text;
                return mText;
            }
            set
            {
                OnSetText(value);
            }
        }

        #region On Set Text
        /// <summary>
        /// Do not raise event TextChanged when this flag is set to true.
        /// </summary>
        protected bool mSuspendTextChangedEvent = false;

        /// <summary>
        /// Set the value of text
        /// </summary>
        protected virtual void OnSetText(string value)
        {
            if (mText != value)
            {
                mText = value;
                mSuspendTextChangedEvent = true;
                if (InvokeRequired) Invoke(new EventHandler(DoSetText), this, EventArgs.Empty);
                else Inner.Text = mText;
                mSuspendTextChangedEvent = false;

                //
                // TLN modified on 12-Dec-2009 
                // for fix bug text box do not refresh text in transparent mode.
                //
                #region Old code
                //if (Transparent) RecreateHandle();
                //else Invalidate();
                #endregion

                #region fixed code
                InvalidateLayout();
                #endregion
            }
        }
        #endregion

        void DoSetText(object sender, EventArgs e)
        {
            Inner.Text = mText;
        }

        #endregion

        #region Text When Null
        private string mTextWhenNull = string.Empty;
        /// <summary>
        /// Gets/Sets the hinting text to display when property Text is empty.
        /// </summary>
        [Browsable(true), DefaultValue(""), Category("Appearance"), Description("Hinting text when property Text is empty")]
        public string TextWhenNull
        {
            get { return mTextWhenNull; }
            set
            {
                mTextWhenNull = value;
                Invalidate();
            }
        }
        #endregion

        #region Title
        private string mTitle = "Title";
        /// <summary>
        /// Gets/Sets the display label of this control.
        /// </summary>
        [Browsable(true), DefaultValue("Title"), Category("Appearance"), Description("Label of this control")]
        public string Title
        {
            get { return mTitle; }
            set
            {
                mTitle = value;
                Invalidate();
            }
        }
        #endregion

        #region Title Style
        private TextStyle mTitleStyle = TextStyle.Normal;
        /// <summary>
        /// Gets/Sets style of title.
        /// </summary>
        [Browsable(true), DefaultValue(TextStyle.Normal), Category("Appearance"), Description("Text style for title")]
        public TextStyle TitleStyle
        {
            get { return mTitleStyle; }
            set
            {
                mTitleStyle = value;
                Invalidate();
            }
        }
        #endregion

        #region Title Layout
        private ContentAlignment mTitleLayout = ContentAlignment.MiddleLeft;
        /// <summary>
        /// Gets/Sets layout of title region.
        /// </summary>
        [Browsable(true), DefaultValue(ContentAlignment.MiddleLeft), Category("Appearance"), Description("Layout of title region")]
        public ContentAlignment TitleLayout
        {
            get { return mTitleLayout; }
            set
            {
                mTitleLayout = value;
                InvalidateLayout();
            }
        }
        #endregion

        #region Text Width
        private int mTextWidth = 100;
        /// <summary>
        /// Gets/Sets horizontal size of Text region.
        /// </summary>
        [Browsable(true), DefaultValue(100), Category("Appearance"), Description("Horizontal size of Text region")]
        public int TextWidth
        {
            get { return mTextWidth; }
            set
            {
                mTextWidth = value;
                InvalidateLayout();
            }
        }
        #endregion

        #region Text Height
        private int mTextHeight = 22;
        /// <summary>
        /// Gets/Sets vertical size of Text region.
        /// </summary>
        [Browsable(true), DefaultValue(22), Category("Appearance"), Description("Vertical size of Text region")]
        public int TextHeight
        {
            get { return mTextHeight; }
            set
            {
                mTextHeight = value;
                InvalidateLayout();
            }
        }
        #endregion

        #region Password Char
        private char mPasswordChar = '\0';
        /// <summary>
        /// Gets/Sets the character to be used in place of text to mask text.
        /// </summary>
        [Browsable(true), DefaultValue('\0'), Category("Appearance"), Description("The character to mask text with")]
        public char PasswordChar
        {
            get { return Inner.PasswordChar; }
            set
            {
                Inner.PasswordChar = value;
                Invalidate();
            }
        }
        #endregion

        #region Read Only
        /// <summary>
        /// Gets/Sets whether this control allows editing.
        /// </summary>
        [Browsable(true), DefaultValue(false), Category("Behavior"), Description("Whether content editing is alllowed")]
        public bool ReadOnly
        {
            get { return Inner.ReadOnly; }
            set { Inner.ReadOnly = value; }
        }
        #endregion

        #region Icon
        private Image mIcon;
        /// <summary>
        /// Gets/Sets the icon representing this edit box.
        /// </summary>
        [Browsable(true), DefaultValue(null), Category("Appearance"), Description("Icon representing this edit box")]
        public Image Icon
        {
            get { return mIcon; }
            set
            {
                mIcon = value;

                //automatically set show icon to true
                if ((mIcon != null) && (!mShowIcon)) mShowIcon = true;
                #region Defensive tracing
                else
                {
                    //not interested in other configuration
                }
                #endregion

                InvalidateLayout();
            }
        }
        #endregion

        #region Icon Style
        private IconStyle mIconStyle = IconStyle.Custom;
        /// <summary>
        /// Gets/Sets the pre-defined icon styles.
        /// </summary>
        [Browsable(true), DefaultValue(IconStyle.Custom), Category("Appearance"), Description("Pre-defined icon style")]
        public IconStyle IconStyle
        {
            get { return mIconStyle; }
            set
            {
                mIconStyle = value;
                ApplyIconStyle();
                InvalidateLayout();
            }
        }

        /// <summary>
        /// Apply the selected icon 
        /// </summary>
        protected virtual void ApplyIconStyle()
        {
            if (mRenderContext != null)
            {
                if (mIconStyle == IconStyle.Custom)
                {
                    mRenderContext.Icon = mIcon;
                }
                else
                {
                    mRenderContext.Icon = EffectiveTheme.FindImage(string.Format("{0}", mIconStyle));
                }
            }
            #region Defensive tracing
            else
            {
                // do not process on null object value.
            }
            #endregion
        }
        #endregion

        #region Show Icon
        private bool mShowIcon = false;
        /// <summary>
        /// Gets/Sets whether this box should render the icon.
        /// </summary>
        [Browsable(true), DefaultValue(false), Category("Appearance"), Description("Display icon at left")]
        public bool ShowIcon
        {
            get { return mShowIcon; }
            set
            {
                mShowIcon = value;
                InvalidateLayout();
            }
        }
        #endregion

        #region Scrollers
        /// <summary>
        /// Gets/Sets the visibility settings for scrollers.
        /// </summary>
        [Browsable(true), DefaultValue(ScrollerVisibility.None), Category("Appearance"), Description("How to display scrollers")]
        public ScrollerVisibility Scrollers
        {
            get { return OnGetScroller(); }
            set
            {
                OnSetScroller(value);
            }
        }

        #region On Set Scroller
        void OnSetScroller(ScrollerVisibility value)
        {
            switch (value)
            {
                case ScrollerVisibility.None:
                    Inner.ScrollBars = ScrollBars.None;
                    break;
                case ScrollerVisibility.Horizontal:
                    Inner.ScrollBars = ScrollBars.Horizontal;
                    break;
                case ScrollerVisibility.Vertical:
                    Inner.ScrollBars = ScrollBars.Vertical;
                    break;
                case ScrollerVisibility.Both:
                    Inner.ScrollBars = ScrollBars.Both;
                    break;
                case ScrollerVisibility.Auto:
                    Inner.ScrollBars = ScrollBars.Both;
                    break;
                default:
                    Inner.ScrollBars = ScrollBars.Both;
                    break;
            }
        }
        #endregion

        #region On Get Scroller
        ScrollerVisibility OnGetScroller()
        {
            ScrollerVisibility result;

            switch (Inner.ScrollBars)
            {
                case ScrollBars.Both:
                    result = ScrollerVisibility.Both;
                    break;
                case ScrollBars.Horizontal:
                    result = ScrollerVisibility.Horizontal;
                    break;
                case ScrollBars.None:
                    result = ScrollerVisibility.None;
                    break;
                case ScrollBars.Vertical:
                    result = ScrollerVisibility.Vertical;
                    break;
                default:
                    result = ScrollerVisibility.Auto;
                    break;
            }

            return result;
        }
        #endregion

        #endregion

        #region Selection Start
        /// <summary>
        /// Gets/Sets starting index of text selection.
        /// </summary>
        [Browsable(true), DefaultValue(0), Category("Data"), Description("Starting index of text selection")]
        public int SelectionStart
        {
            get { return Inner.SelectionStart; }
            set { Inner.SelectionStart = value; }
        }
        #endregion

        #region Selection Length
        /// <summary>
        /// Gets/Sets number of characters selected.
        /// </summary>
        [Browsable(true), DefaultValue(0), Category("Data"), Description("Number of characters selected")]
        public int SelectionLength
        {
            get { return Inner.SelectionLength; }
            set { Inner.SelectionLength = value; }
        }
        #endregion

        #region Render Context
        private EditBoxRenderContext mRenderContext = null;
        /// <summary>
        /// Gets reference to current renderation context.
        /// </summary>
        protected EditBoxRenderContext RenderContext
        {
            get
            {
                //ensure the value is initialized
                if (mRenderContext == null) mRenderContext = OnCreateRenderContext();
                #region Defensive tracing
                else
                {
                    //already initialized
                }
                #endregion

                return mRenderContext;
            }
        }
        #endregion

        #endregion

        #region Events

        #region Key Down
        /// <summary>
        /// This event is raised after a key is depressed.
        /// </summary>
        public new event KeyEventHandler KeyDown;

        /// <summary>
        /// Invoke event KeyDown
        /// </summary>
        protected void RaiseKeyDown(KeyEventArgs args)
        {
            KeyEventHandler handler = KeyDown;
            if (handler != null) handler(this, args);
        }
        #endregion

        #region Key Up
        /// <summary>
        /// This event is raised after a key is released.
        /// </summary>
        public new event KeyEventHandler KeyUp;

        /// <summary>
        /// Invoke event KeyUp
        /// </summary>
        protected void RaiseKeyUp(KeyEventArgs args)
        {
            KeyEventHandler handler = KeyUp;
            if (handler != null) handler(this, args);
        }
        #endregion

        #region Key Press
        /// <summary>
        /// This event is raised after a key is pressed (depressed then released)
        /// </summary>
        public new event KeyPressEventHandler KeyPress;

        /// <summary>
        /// Invoke event KeyPress
        /// </summary>
        protected void RaiseKeyPress(KeyPressEventArgs args)
        {
            KeyPressEventHandler handler = KeyPress;
            if (handler != null) handler(this, args);
        }
        #endregion

        #region Enter Key
        /// <summary>
        /// This event is raised after key Enter was depressed.
        /// </summary>
        [Browsable(true), Category("Key"), Description("Occurs when key Enter is pressed.")]
        public event EventHandler EnterKeyPressed;

        /// <summary>
        /// Invoke event EnterKey
        /// </summary>
        protected void RaiseEnterKeyPressed(EventArgs args)
        {
            EventHandler handler = EnterKeyPressed;
            if (handler != null) handler(this, args);
        }
        #endregion

        #region Got Focus
        /// <summary>
        /// This event is raised after this control received focus.
        /// </summary>
        public new event EventHandler GotFocus;

        /// <summary>
        /// Invoke event GotFocus.
        /// </summary>
        protected void RaiseGotFocus()
        {
            EventHandler handler = GotFocus;
            if (handler != null) handler(this, EventArgs.Empty);
        }
        #endregion

        #region Inner Text Changed
        /// <summary>
        /// This event is raised when property Text of the inner textbox is changed.
        /// </summary>
        protected event EventHandler InnerTextChanged;

        /// <summary>
        /// Invoke event InnerTextChanged
        /// </summary>
        protected void RaiseInnerTextChanged()
        {
            EventHandler handler = InnerTextChanged;
            if (handler != null) handler(this, EventArgs.Empty);
        }
        #endregion

        #region Drop Button Click
        /// <summary>
        /// This event is raised after drop button is clicked.
        /// </summary>
        public event MouseEventHandler DropButtonClick;
        /// <summary>
        /// Invoke event DropButtonClick.
        /// </summary>
        protected void RaiseDropButtonClick(MouseEventArgs args)
        {
            MouseEventHandler handler = DropButtonClick;
            if (handler != null) handler(this, args);
        }
        #endregion

        #region Value Changed
        /// <summary>
        /// This event is raised after the main property of this control is modified.
        /// <para>The main property may be different for each specific concrete editbox control.</para>
        /// </summary>
        public event EventHandler ValueChanged;

        /// <summary>
        /// Invoke event ValueChanged
        /// </summary>
        protected void RaiseValueChanged(EventArgs args)
        {
            EventHandler handler = ValueChanged;
            if (handler != null) handler(this, args);
        }
        #endregion

        #endregion

        #region On Get Render Context
        /// <summary>
        /// Get reference to the renderation context which is used by <see cref="IControlRenderer"/>.
        /// </summary>
        protected override RenderContext OnGetRenderContext(Graphics canvas)
        {
            return RenderContext;
        }
        #endregion

        #region On Calculate Layout
        /// <summary>
        /// Perform layout calculations neccessary for this control.
        /// </summary>
        protected override void OnCalculateLayout()
        {
            Padding pad = this.Padding;
            Rectangle rCon = this.ClientRectangle;
            rCon = new Rectangle(rCon.Left, rCon.Top, rCon.Width - 1, rCon.Height - 1);//fix pixel offset bug
            Rectangle rTitle = Rectangle.Empty;
            Rectangle rEdit = Rectangle.Empty;
            Rectangle rIcon = Rectangle.Empty;
            Rectangle rButton = Rectangle.Empty;
            Rectangle rText = Rectangle.Empty;
            Rectangle r = Rectangle.Empty;
            int w = 0;
            int h = 0;

            #region Preliminary phase - layout title & edit region

            r = rCon;

            switch (mTitleLayout)
            {
                #region Bottom Center
                case ContentAlignment.BottomCenter:
                    rEdit = new Rectangle(r.Left + pad.Left, r.Top + pad.Top, r.Width - pad.Left - pad.Right, mTextHeight);
                    h = r.Height - mTextHeight - pad.Bottom * 2 - pad.Top;
                    rTitle = new Rectangle(rEdit.Left, rEdit.Bottom + pad.Bottom, rEdit.Width, h);
                    break;
                #endregion

                #region Bottom Left
                case ContentAlignment.BottomLeft:
                    rEdit = new Rectangle(r.Left + pad.Left, r.Top + pad.Top, r.Width - pad.Left - pad.Right, mTextHeight);
                    h = r.Height - mTextHeight - pad.Bottom * 2 - pad.Top;
                    rTitle = new Rectangle(rEdit.Left, rEdit.Bottom + pad.Bottom, rEdit.Width, h);
                    break;
                #endregion

                #region Bottom Right
                case ContentAlignment.BottomRight:
                    rEdit = new Rectangle(r.Left + pad.Left, r.Top + pad.Top, r.Width - pad.Left - pad.Right, mTextHeight);
                    h = r.Height - mTextHeight - pad.Bottom * 2 - pad.Top;
                    rTitle = new Rectangle(rEdit.Left, rEdit.Bottom + pad.Bottom, rEdit.Width, h);
                    break;
                #endregion

                #region Middle Center
                case ContentAlignment.MiddleCenter:
                    //do not show title
                    rTitle = Rectangle.Empty;
                    rEdit = rCon;
                    break;
                #endregion

                #region Middle Left
                case ContentAlignment.MiddleLeft:
                    rEdit = new Rectangle(r.Right - pad.Right - mTextWidth, r.Top + pad.Top, mTextWidth, r.Height - pad.Top - pad.Bottom);
                    w = r.Width - rEdit.Width - pad.Left * 2 - pad.Right;
                    rTitle = new Rectangle(r.Left + pad.Left, rEdit.Top, w, rEdit.Height);
                    break;
                #endregion

                #region Middle Right
                case ContentAlignment.MiddleRight:
                    rEdit = new Rectangle(r.Left + pad.Left, r.Top + pad.Top, mTextWidth, r.Height - pad.Top - pad.Bottom);
                    w = r.Width - rEdit.Width - pad.Left * 2 - pad.Right;
                    rTitle = new Rectangle(rEdit.Right + pad.Left, rEdit.Top, w, rEdit.Height);
                    break;
                #endregion

                #region Top Center
                case ContentAlignment.TopCenter:
                    rEdit = new Rectangle(r.Left + pad.Left, r.Bottom - pad.Bottom - mTextHeight, r.Width - pad.Left - pad.Right, mTextHeight);
                    h = r.Height - rEdit.Height - pad.Top * 2 - pad.Bottom;
                    rTitle = new Rectangle(rEdit.Left, r.Top + pad.Top, rEdit.Width, h);
                    break;
                #endregion

                #region Top Left
                case ContentAlignment.TopLeft:
                    rEdit = new Rectangle(r.Left + pad.Left, r.Bottom - pad.Bottom - mTextHeight, r.Width - pad.Left - pad.Right, mTextHeight);
                    h = r.Height - rEdit.Height - pad.Top * 2 - pad.Bottom;
                    rTitle = new Rectangle(rEdit.Left, r.Top + pad.Top, rEdit.Width, h);
                    break;
                #endregion

                #region Top Right
                case ContentAlignment.TopRight:
                    rEdit = new Rectangle(r.Left + pad.Left, r.Bottom - pad.Bottom - mTextHeight, r.Width - pad.Left - pad.Right, mTextHeight);
                    h = r.Height - rEdit.Height - pad.Top * 2 - pad.Bottom;
                    rTitle = new Rectangle(rEdit.Left, r.Top + pad.Top, rEdit.Width, h);
                    break;
                #endregion

                #region Default
                default:
                    break;
                #endregion
            }
            #endregion

            #region Secondary phase - layout within edit region
            r = rEdit;
            h = r.Height - pad.All * 2;

            if (mShowIcon) rIcon = new Rectangle(r.Left + pad.All, r.Top + pad.All, h, h);
            else rIcon = new Rectangle(r.Left + pad.All, r.Top + pad.All, 0, 0);

            if (mShowDropButton) rButton = new Rectangle(r.Right - pad.All - h, rIcon.Top, h, h);
            else rButton = new Rectangle(r.Right - pad.All, rIcon.Top, 0, 0);

            rText = new Rectangle(rIcon.Right + pad.All, rIcon.Top, rButton.Left - rIcon.Right - pad.All * 2, h);

            //rEdit = new Rectangle(rIcon.Left, rIcon.Top, rButton.Right - rIcon.Left, h);

            #endregion

            #region Assign values to render context
            EditBoxRenderContext context = RenderContext;
            context.ControlRegion = rCon;
            context.TitleRegion = rTitle;
            context.EditRegion = rEdit;

            context.IconRegion = rIcon;
            context.ButtonRegion = rButton;
            context.TextRegion = rText;
            #endregion

            #region Adjust boundary of inner textbox
            int offset = 1;
            r = rText;
            r = new Rectangle(r.Left, r.Top, r.Width, r.Height);
            Inner.SetBounds(r.Left + offset, r.Top + offset, r.Width - offset * 2, r.Height - offset * 2);
            #endregion

            #region Previous
            /*
            #region Preliminary phase - layout title & edit region
            switch (mTitleLayout)
            {
                #region Bottom Center
                case ContentAlignment.BottomCenter:
                    rTitle = new Rectangle(r.Left + pad.Left, r.Bottom - pad.Bottom - mTitleHeight, r.Width - pad.Left - pad.Right, mTitleHeight);
                    h = r.Height - rTitle.Height - pad.Top - pad.Bottom * 2;
                    rEdit = new Rectangle(rTitle.Left, rTitle.Top - pad.Bottom - h, rTitle.Width, h);
                    break;
                #endregion

                #region Bottom Left
                case ContentAlignment.BottomLeft:
                    rTitle = new Rectangle(r.Left + pad.Left, r.Bottom - pad.Bottom - mTitleHeight, r.Width - pad.Left - pad.Right, mTitleHeight);
                    h = r.Height - rTitle.Height - pad.Top - pad.Bottom * 2;
                    rEdit = new Rectangle(rTitle.Left, rTitle.Top - pad.Bottom - h, rTitle.Width, h);
                    break;
                #endregion

                #region Bottom Right
                case ContentAlignment.BottomRight:
                    rTitle = new Rectangle(r.Left + pad.Left, r.Bottom - pad.Bottom - mTitleHeight, r.Width - pad.Left - pad.Right, mTitleHeight);
                    h = r.Height - rTitle.Height - pad.Top - pad.Bottom * 2;
                    rEdit = new Rectangle(rTitle.Left, rTitle.Top - pad.Bottom - h, rTitle.Width, h);
                    break;
                #endregion

                #region Middle Center
                case ContentAlignment.MiddleCenter:
                    break;
                #endregion

                #region Middle Left
                case ContentAlignment.MiddleLeft:
                    rTitle = new Rectangle(r.Left + pad.Left, r.Top + pad.Top, mTitleWidth, r.Height - pad.Top - pad.Bottom);
                    w = r.Width - rTitle.Width - pad.Left * 2 - pad.Right;
                    rEdit = new Rectangle(rTitle.Right + pad.Left, rTitle.Top, w, rTitle.Height);
                    break;
                #endregion

                #region Middle Right
                case ContentAlignment.MiddleRight:
                    rTitle = new Rectangle(r.Right - pad.Right - mTitleWidth, r.Top + pad.Top, mTitleWidth, r.Height - pad.Top - pad.Bottom);
                    w = rTitle.Left - r.Left - pad.Left * 2;
                    rEdit = new Rectangle(r.Left + pad.Left, rTitle.Top, w, rTitle.Height);
                    break;
                #endregion

                #region Top Center
                case ContentAlignment.TopCenter:
                    rTitle = new Rectangle(r.Left + pad.Left, r.Top + pad.Top, r.Width - pad.Left - pad.Right, mTitleHeight);
                    h = r.Height - rTitle.Height - pad.Top * 2 - pad.Bottom;
                    rEdit = new Rectangle(rTitle.Left, rTitle.Bottom + pad.Top, rTitle.Width, h);
                    break;
                #endregion

                #region Top Left
                case ContentAlignment.TopLeft:
                    rTitle = new Rectangle(r.Left + pad.Left, r.Top + pad.Top, r.Width - pad.Left - pad.Right, mTitleHeight);
                    h = r.Height - rTitle.Height - pad.Top * 2 - pad.Bottom;
                    rEdit = new Rectangle(rTitle.Left, rTitle.Bottom + pad.Top, rTitle.Width, h);
                    break;
                #endregion

                #region Top Right
                case ContentAlignment.TopRight:
                    rTitle = new Rectangle(r.Left + pad.Left, r.Top + pad.Top, r.Width - pad.Left - pad.Right, mTitleHeight);
                    h = r.Height - rTitle.Height - pad.Top * 2 - pad.Bottom;
                    rEdit = new Rectangle(rTitle.Left, rTitle.Bottom + pad.Top, rTitle.Width, h);
                    break;
                #endregion

                #region Default
                default:
                    break;
                #endregion
            }
            #endregion

            #region Secondary phase - layout within edit region
            r = rEdit;
            h = r.Height - pad.All * 2;

            if (mShowIcon) rIcon = new Rectangle(r.Left + pad.All, r.Top + pad.All, h, h);
            else rIcon = new Rectangle(r.Left + pad.All, r.Top + pad.All, 0, 0);

            if (mShowDropButton) rButton = new Rectangle(r.Right - pad.All - h, rIcon.Top, h, h);
            else rButton = new Rectangle(r.Right - pad.All, rIcon.Top, 0, 0);

            rText = new Rectangle(rIcon.Right + pad.All, rIcon.Top, rButton.Left - rIcon.Right - pad.All * 2, h);

            //rEdit = new Rectangle(rIcon.Left, rIcon.Top, rButton.Right - rIcon.Left, h);

            #endregion

            #region Assign values to render context
            EditBoxRenderContext context = RenderContext;
            context.ControlRegion = rCon;
            context.TitleRegion = rTitle;
            context.EditRegion = rEdit;

            context.IconRegion = rIcon;
            context.ButtonRegion = rButton;
            context.TextRegion = rText;
            #endregion
            */

            #endregion

            #region Old codes
            /*

            #region Layout edit region
            int pad = 0;
            Rectangle r = this.ClientRectangle;
            r = new Rectangle(r.Left, r.Top, r.Width - 1, r.Height - 1);//fix pixel offset bug
            int h = r.Height - pad * 2;
            Rectangle rIcon;
            Rectangle rButton;
            Rectangle rText;
            Rectangle rEdit;

            if (mShowIcon) rIcon = new Rectangle(r.Left + pad, r.Top + pad, h, h);
            else rIcon = new Rectangle(r.Left + pad, r.Top + pad, 0, 0);

            if (mShowDropButton) rButton = new Rectangle(r.Right - pad - h, rIcon.Top, h, h);
            else rButton = new Rectangle(r.Right - pad, rIcon.Top, 0, 0);

            rText = new Rectangle(rIcon.Right + pad, rIcon.Top, rButton.Left - rIcon.Right - pad * 2, h);

            rEdit = new Rectangle(rIcon.Left, rIcon.Top, rButton.Right - rIcon.Left, h);
            #endregion

            //assign value to render context
            EditBoxRenderContext rc = RenderContext;
            rc.IconRegion = rIcon;
            rc.ButtonRegion = rButton;
            rc.TextRegion = rText;
            rc.EditRegion = rEdit;

            //adjust inner textbox
            int offset = 1;
            Inner.SetBounds(rText.Left + offset, rText.Top + offset, rText.Width - offset * 1, rText.Height - offset * 1);
            */
            #endregion
        }
        #endregion

        #region On Create Render Context
        /// <summary>
        /// Create a new render context instance.
        /// </summary>
        protected abstract EditBoxRenderContext OnCreateRenderContext();
        #endregion

        #region On Got Focus
        protected override void OnGotFocus(EventArgs e)
        {
            if (Inner.Visible == false && !ReadOnly)
            {
                ShowInnerTextBox();
                InvalidateLayout();
            }
            #region Defensive tracing
            else
            {
                //my inner textbox is already focused
            }
            #endregion
        }
        #endregion

        #region On Lost Focus
        protected override void OnLostFocus(EventArgs e)
        {
            if (mRenderContext != null)
            {
                //update render context
                mRenderContext.IsMouseOver = false;
            }
            #region Defensive tracing
            else
            {

            }
            #endregion
            base.OnLostFocus(e);
            Invalidate();
        }
        #endregion

        #region On Drop Button Down
        /// <summary>
        /// This method will be called after user click on drop button.
        /// </summary>
        protected virtual void OnDropButtonDown(MouseEventArgs e)
        {
        }
        #endregion

        #region Create Inner Text Box
        /// <summary>
        /// Create inner text box control.
        /// </summary>
        protected virtual NativeWindowsTextBox CreateInnerTextBox()
        {
            NativeWindowsTextBox result = new NativeWindowsTextBox();

            result.BorderStyle = BorderStyle.None;
            result.AutoSize = false;
            result.Visible = false;            

            return result;
        }
        #endregion

        #region Show Inner Text Box
        /// <summary>
        /// Turn on inner textbox.
        /// </summary>
        protected virtual void ShowInnerTextBox()
        {
            #region Apply styles for inner textbox
            IEditBoxRenderer renderer = EffectiveRenderer as IEditBoxRenderer;

            if (renderer != null)
            {
                renderer.ApplyStylesForInnerText(this, Inner, RenderContext);
            }
            #region Defensive tracing
            else
            {
                //Log.Warning("Renderer {0} does not implement IEditBoxRenderer, as requried by {0}", EffectiveRenderer, this);
            }
            #endregion

            if (mRenderContext != null)
            {
                Inner.Multiline = mRenderContext.Multiline;

                #region Apply alignment
                switch (RenderContext.Alignment)
                {
                    case ContentAlignment.BottomCenter:
                        Inner.TextAlign = HorizontalAlignment.Center;
                        break;
                    case ContentAlignment.BottomLeft:
                        Inner.TextAlign = HorizontalAlignment.Left;
                        break;
                    case ContentAlignment.BottomRight:
                        Inner.TextAlign = HorizontalAlignment.Right;
                        break;
                    case ContentAlignment.MiddleCenter:
                        Inner.TextAlign = HorizontalAlignment.Center;
                        break;
                    case ContentAlignment.MiddleLeft:
                        Inner.TextAlign = HorizontalAlignment.Left;
                        break;
                    case ContentAlignment.MiddleRight:
                        Inner.TextAlign = HorizontalAlignment.Right;
                        break;
                    case ContentAlignment.TopCenter:
                        Inner.TextAlign = HorizontalAlignment.Center;
                        break;
                    case ContentAlignment.TopLeft:
                        Inner.TextAlign = HorizontalAlignment.Left;
                        break;
                    case ContentAlignment.TopRight:
                        Inner.TextAlign = HorizontalAlignment.Right;
                        break;
                    default:
                        Inner.TextAlign = HorizontalAlignment.Left;
                        break;
                }
                #endregion
            }
            #region Defensive tracing
            else
            {
                // do not get value from null object.
            }
            #endregion


            #endregion

            //Show the inner
            Inner.Visible = true;
            Inner.Focus();

            if (MoveToEndOnFocus)
            {
                Inner.SelectionStart = Inner.Text.Length;
                Inner.SelectionLength = 0;
            }
            else
            {
                //auto select text
                Inner.SelectionStart = 0;
                Inner.SelectionLength = Inner.Text.Length;
            }
        }
        #endregion

        #region Hide Inner Text Box
        /// <summary>
        /// Turn off inner textbox.
        /// </summary>
        protected virtual void HideInnerTextBox()
        {
            Inner.Visible = false;
            Invalidate();
        }
        #endregion

        #region Mouse Events

        #region On Mouse Enter
        /// <summary>
        /// Override this method for update mouse over status of render context.
        /// </summary>
        protected override void OnMouseEnter(EventArgs e)
        {
            ((EditBoxRenderContext)OnGetRenderContext(null)).IsMouseOver = true;
            Invalidate();
        }
        #endregion

        #region On Mouse Leave
        /// <summary>
        /// Override this method for update the mouse over state 
        /// and status of drop button from render context.
        /// </summary>
        protected override void OnMouseLeave(EventArgs e)
        {
            ((EditBoxRenderContext)OnGetRenderContext(null)).IsMouseOver = false;
            ButtonState state = mRenderContext.DropButtonState;

            if ((mShowDropButton) && (state == ButtonState.Over))
            {
                state = ButtonState.Normal;
            }
            #region Defensive tracing
            else
            {
                // drop button is not allow to show, do nothing.
            }
            #endregion

            Invalidate();
        }
        #endregion

        #region On Mouse Move
        /// <summary>
        /// Override this method for process on the drop button when mouse move.
        /// </summary>
        protected override void OnMouseMove(MouseEventArgs e)
        {
            if ((mShowDropButton) && (this.Enabled))
            {
                Point p = new Point(e.X, e.Y);

                EditBoxRenderContext rc = mRenderContext;
                bool isHover = ClientRectangle.Contains(p);
                Rectangle rButton = rc.ButtonRegion;
                ButtonState state = rc.DropButtonState;

                if (rButton.Contains(p))
                {
                    if (state != ButtonState.Over)
                    {
                        state = ButtonState.Over;
                    }
                    #region Defensive tracing
                    else
                    {
                        // the drop button is already over.
                    }
                    #endregion
                }
                else if (mRenderContext.IsMouseOver)
                {
                    if (state != ButtonState.Normal)
                    {
                        state = ButtonState.Normal;
                    }
                    #region Defensive tracing
                    else
                    {
                        // the drop button is already over.
                    }
                    #endregion
                }
                #region Defensive tracing
                else
                {
                    state = ButtonState.Normal;
                }
                #endregion

                rc.IsMouseOver = isHover;
                rc.DropButtonState = state;
                InvalidateLayout();
            }
            #region Defensive tracing
            else
            {
                // drop button is turn off, do nothing.
            }
            #endregion


            base.OnMouseMove(e);
        }
        #endregion

        #region On Mouse Down
        /// <summary>
        /// Override this method for process the drop button.
        /// </summary>
        protected override void OnMouseDown(MouseEventArgs e)
        {
            ButtonState state = mRenderContext.DropButtonState;
            if ((mShowDropButton) && (state == ButtonState.Over))
            {
                mRenderContext.DropButtonState = ButtonState.Pressed;
                InvalidateLayout();

                OnDropButtonDown(e);
                RaiseDropButtonClick(e);
            }

            base.OnMouseDown(e);
        }
        #endregion

        #region On Click
        protected override void OnClick(EventArgs e)
        {
            //set focus to this control if not focused yet
            if (!Focused) Focus();
            #region Defensive tracing
            else
            {
                //already focused
            }
            #endregion
        }
        #endregion

        #endregion

        #region Internal Messages

        #region Notify Process Cmd Key
        /// <summary>
        /// This method is called by the inner textbox
        /// </summary>
        internal virtual bool NotifyProcessCmdKey(ref Message msg, Keys keyData)
        {
            bool result = false;

            RaiseOnProcessCmdKey(ref msg, keyData);

            /*
            if (keyData == Keys.Enter)
            {
                RaiseEnterKey(EventArgs.Empty);
                result = true;
            }
            #region Defensive tracing
            else
            {
                //not interested in other keys
            }
            #endregion
            */

            return result;
        }
        #endregion

        #region Events

        #region On Process Cmd Key
        /// <summary>
        /// This event is raised when an event ProcessCmdKey is raised by inner textbox. 
        /// </summary>
        public event ProcessCmdKeyHandler OnProcessCmdKey;

        /// <summary>
        /// Invoke event OnProcessCmdKey
        /// </summary>
        protected void RaiseOnProcessCmdKey(ref Message msg, Keys keyData)
        {
            ProcessCmdKeyHandler handler = OnProcessCmdKey;
            if (handler != null) handler(this, ref msg, keyData);
        }
        #endregion

        #region On Process Dialog Key
        /// <summary>
        /// This event is raised when a ProcessDiaglogKey event is raised from inner textbox. 
        /// </summary>
        public event ProcessDialogKeyHandler OnProcessDialogKey;

        /// <summary>
        /// Invoke event OnProcessDialogKey
        /// </summary>
        protected void RaiseOnProcessDialogKey(Keys keyData)
        {
            ProcessDialogKeyHandler handler = OnProcessDialogKey;
            if (handler != null) handler(this, keyData);
        }
        #endregion

        #endregion

        #region Notify Process Dialog Key
        /// <summary>
        /// This method is called by the inner textbox
        /// </summary>
        internal virtual bool NotifyInnerTextBoxProcessDialogKey(Keys keyData)
        {
            bool result = false;

            RaiseOnProcessDialogKey(keyData);

            return result;
        }
        #endregion

        #region Notify On Key Press
        /// <summary>
        /// This method is raised by the inner textbox to notify that it has received a keypress event
        /// </summary>
        internal virtual void NotifyInnerTextBoxOnKeyPress(KeyPressEventArgs e)
        {
            RaiseKeyPress(e);
            if (e.KeyChar == (char)Keys.Enter)
            {
                RaiseEnterKeyPressed(EventArgs.Empty);
            }
            #region Defensive tracing
            else
            {
                //not interested in other keys
            }
            #endregion
        }
        #endregion

        #region Notify On Key Down
        /// <summary>
        /// This method is raised by the inner textbox to notify that it has received a keydown event
        /// </summary>
        internal virtual void NotifyInnerTextBoxOnKeyDown(KeyEventArgs e)
        {
            RaiseKeyDown(e);
        }
        #endregion

        #region Notify On Key Up
        /// <summary>
        /// This method will be called after key up.
        /// </summary>
        internal virtual void NotifyInnerTextBoxOnKeyUp(KeyEventArgs e)
        {
            RaiseKeyUp(e);
        }
        #endregion

        #region Notify On Text Changed
        /// <summary>
        /// This method is raised by the inner textbox to notify that its text has changed
        /// </summary>
        internal virtual void NotifyInnerTextBoxOnTextChanged()
        {
            RaiseInnerTextChanged();

            if (!mSuspendTextChangedEvent)
            {
                mText = Inner.Text;
                OnTextChanged(EventArgs.Empty);
            }
        }
        #endregion

        #region Notify On Lost Focus
        /// <summary>
        /// This method will be called after the control is lost focus
        /// </summary>
        internal virtual void NotifyInnerTextBoxOnLostFocus(EventArgs e)
        {
            //update render context
            mRenderContext.IsMouseOver = false;

            if (!this.Focused)
            {
                HideInnerTextBox();
            }
            #region Defensive tracing
            else
            {
                //still within this control, don't turn off inner
                //Invalidate();
            }
            #endregion
        }
        #endregion

        #region Notify On Mouse Enter
        /// <summary>
        /// This method is raised by the inner textbox to notify that the mouse pointer is move enter.
        /// </summary>
        internal virtual void NotifyInnerTextBoxOnMouseEnter(EventArgs e)
        {
            mRenderContext.IsMouseOver = true;
            mRenderContext.DropButtonState = ButtonState.Normal;
        }
        #endregion

        #region Notify On Mouse Leave
        /// <summary>
        /// This method is raised by the inner textbox to notify that the mouse pointer is move out.
        /// </summary>
        internal virtual void NotifyInnerTextBoxOnMouseLeave(EventArgs e)
        {
            //mRenderContext.IsMouseOver = false;
        }
        #endregion

        #region Notify On Mouse Down
        /// <summary>
        /// This method is raised by the inner textbox to notify that user press mouse on the control.
        /// </summary>
        internal virtual void NotifyInnerTextBoxOnMouseDown(MouseEventArgs e)
        {
            //mRenderContext.IsMouseOver = false;
        }
        #endregion

        #endregion

        #region Constructors
        /// <summary>
        /// Default constructor.
        /// </summary>
        public EditBox()
        {
            //force creating render context
            EditBoxRenderContext rc = this.RenderContext;
            this.Size = new Size(175, 22);

            Inner = CreateInnerTextBox();
            this.Controls.Add(Inner);
        }
        #endregion
    }
}
